-
Notifications
You must be signed in to change notification settings - Fork 150
feat: add google adk plugins #1282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
|
|
|
||
| @staticmethod | ||
| @activity.defn(dynamic=True) | ||
| async def dynamic_activity(args: Sequence[RawValue]) -> Any: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not great to make this a dynamic activity. That would mean the application author could not use a dynamic activity of their own, and we discourage their use now. Instead, just call it invoke_model or some such, and set a summary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'll also simplify the argument handling.
|
|
||
| # Execute with dynamic name | ||
| response_dicts = await workflow.execute_activity( | ||
| activity_name, args=[llm_request], **self.activity_options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can set the summary here to be whatever you want. That will show up in the UI as "activity_name - summary"
| class AdkWorkflowInboundInterceptor(WorkflowInboundInterceptor): | ||
| async def execute_workflow(self, input: ExecuteWorkflowInput) -> Any: | ||
| # Global runtime setup before ANY user code runs | ||
| setup_deterministic_runtime() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the things you can do with a plugin is run some code around the worker execution. It seems likely this could be a context manager in run_context. See set_open_ai_agent_temporal_overrides in the OpenAI agents plugin for an example.
| ] | ||
|
|
||
| # 5. Serialization | ||
| # Return dicts to avoid Pydantic strictness issues on rehydration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious to know why this is needed. Might be nice to fix at the converter instead. We had to do something similar to slightly customize the pydantic converter for openai. If an option like by_alias in ToJsonOptions would fix it, that might be a better route.
| from temporalio.worker import UnsandboxedWorkflowRunner | ||
|
|
||
| # TODO: Not sure implications here. is this a good default an allow user override? | ||
| return UnsandboxedWorkflowRunner() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unconditionally disabling the sandbox isn't great. Usually you would pass through some libraries that you are promising to use correctly.
Google ADK Agents SDK Integration for Temporal
This package provides the integration layer between the Google ADK and Temporal. It allows ADK Agents to run reliably within Temporal Workflows by ensuring determinism and correctly routing external calls (network I/O) through Temporal Activities.
Core Concepts
1. Interception Flow (
AgentPlugin)The
AgentPluginacts as a middleware that intercepts model calls (e.g.,agent.generate_content) before they execute.Workflow Interception:
before_model_callbackwhen an agent attempts to call a model.workflow.execute_activity(), routing the request to Temporal for execution.This ensures that all model interactions are recorded in the Temporal Workflow history, enabling reliable replay and determinism.
2. Dynamic Activity Registration
To provide visibility in the Temporal UI, activities are dynamically named after the calling agent (e.g.,
MyAgent.generate_content). Since agent names are not known at startup, the integration uses Temporal's dynamic activity registration.When the workflow executes an activity with an unknown name (e.g.,
MyAgent.generate_content), the worker routes the call todynamic_activity. This handler inspects theactivity_typeand delegates execution to the appropriate internal logic (_handle_generate_content), enabling arbitrary activity names without explicit registration.3. Usage & Configuration
The integration requires setup on both the Agent (Workflow) side and the Worker side.
Agent Setup (Workflow Side)
Attach the
AgentPluginto your ADK agent. This safely routes model calls through Temporal activities. You must provide activity options (e.g., timeouts) as there are no defaults.Worker Setup
Install the
WorkerPluginon your Temporal Worker. This handles serialization and runtime determinism.What
WorkerPluginDoes:time.time,uuid.uuid4) before workflow execution.UnsandboxedWorkflowRunner, allowing standard imports in ADK agents.